//    Copyright (C) Kherty.  All rights reserved.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.Contracts;
using System.IO;
using OpenLS.Spreadsheet.Expressions;
using OpenLS.Spreadsheet.Functions;

namespace OpenLS.Spreadsheet.Formats.Biff.Tokens
{
    internal class FunctionToken : FunctionTokenBase
    {
        public FunctionToken(AccessorType type): base (type)
        {
        }

        public FunctionToken(AccessorType type, BuiltInFunctionId functionId): base (type, functionId)
        {
            Contract.Requires(functionId != BuiltInFunctionId.SEARCH);
        }

        public override ushort GetLength(FormulaReadContextType formulaReadContextType)
        {
            return 2;
        }
        public override FormulaTokenId TokenId
        {
            get {
                switch (_type)
                {
                    case AccessorType.Array: return FormulaTokenId.FuncA;
                        case AccessorType.Reference:
                        return FormulaTokenId.Func;
                        case AccessorType.Value:
                        return FormulaTokenId.FuncV;
                    default:
                        throw new NotSupportedException();

                }
            }
        }

        internal override void ReadContent(FormulaReadContext context)
        {
            _functionId = (BuiltInFunctionId) context.ReadUInt16();
        }
        public override void WriteContent(FormulaWriteContext context)
        {
            context.WriteUInt16((ushort) _functionId);
        }
        internal override Expression GetExpression(FormulaEvaluationContext context)
        {
            string s = _functionId.ToString();
            Function function = context.Workbook.Document.Context.GetFunction(s, false);
            if (function == null)
                function = new UnknownFunction(s);
            int parameterCount = function.MaximumParameterCount;
            var arguments = new List<Expression>();
            for (int i = 0; i < parameterCount; i++)
            {
                FormulaToken poped = context.PoppedArgument();
                Expression expression = poped.GetExpression(context);
                if (expression != null)
                    arguments.Add(expression);
                else if (context.Arguments.Count != 0)
                    throw new InvalidOperationException("null expression");
            }
            arguments.Reverse();
            return new FunctionInvokeExpression(function, arguments, context.Workbook.Document.Context);
        }
    }
}